package com.tiancheng.trade.payment.service.impl;

import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.enums.SettleRuleTypeEnums;
import com.tiancheng.trade.commom.core.exception.Asserts;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.commom.web.cache.MerchantCache;
import com.tiancheng.trade.commom.web.feign.MerchantFeignService;
import com.tiancheng.trade.commom.web.model.request.OrderMerchantSettleReqVO;
import com.tiancheng.trade.commom.web.cache.model.MerchantBO;
import com.tiancheng.trade.payment.feign.SettlementRuleService;
import com.tiancheng.trade.commom.web.model.response.SettlementRuleResVO;
import com.tiancheng.trade.commom.web.model.request.MerchantChannelRequestDTO;
import com.tiancheng.trade.commom.web.model.response.MerchantChannelResponseDTO;
import com.tiancheng.trade.payment.service.PaymentMerchantPlatformService;
import com.tiancheng.trade.payment.service.SettlePlatformService;
import com.tiancheng.trade.payment.util.cache.PaymentCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台抽佣服务
 *
 * @Date 2024/11/18
 * @Author DCH
 */
@Service
@Slf4j
public class SettlePlatformServiceImpl implements SettlePlatformService {

    @Resource
    private SettlementRuleService settlementRuleService;
    @Resource
    private MerchantFeignService merchantFeignService;
    @Resource
    private PaymentMerchantPlatformService paymentMerchantPlatformService;

    /**
     * 计算子订单平台抽佣金额
     * 规则1：只要是自营、平台类型的清分规则，平台抽佣为0，订单金额全部划付给腾云子商户
     * 规则2：清分百分比商品，平台抽佣金额=子订单金额*百分比
     * 规则3：清分平台固定金额商品，平台抽佣金额=平台固定金额
     * 规则4：清分商户固定金额商品，平台抽佣金额=子订单金额-商户固定金额
     *
     * @param subAmount    子订单金额
     * @param productId    商品编码
     * @param productCount 商品数量
     * @param ruleMap      清分规则集合（key=productId, value=SettlementRuleDTO）
     * @return Long
     */
    @Override
    public Integer countSubPlatformAmount(Integer subAmount, String productId, Integer productCount, Map<String, SettlementRuleResVO> ruleMap) {
        // 自营、平台默认平台抽佣金额为0
        int platformAmount = 0;
        // 查无清分规则
        if (null == ruleMap.get(productId)) {
            log.error("为查询到商品清分规则，productId：{}", productId);
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_NO_RULE, null, BusinessErrorInfoEnum.CHANNEL_PAY_NO_RULE.getMessage());
        }
        // 清分
        if (SettlementRuleResVO.SETTLEMENT_TYPE_CLEAR.equals(ruleMap.get(productId).getSettlementType())) {
            if (SettlementRuleResVO.CLEARING_RULE_RATE.equals(ruleMap.get(productId).getClearingRule())) {
                // 百分比
                platformAmount = ruleMap.get(productId).getPlatformPre().multiply(new BigDecimal(subAmount)).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).intValue();
            } else if (SettlementRuleResVO.CLEARING_RULE_NUM_P.equals(ruleMap.get(productId).getClearingRule())) {
                // 平台固定金额
                platformAmount = ruleMap.get(productId).getPlatformFix() * productCount;
            } else if (SettlementRuleResVO.CLEARING_RULE_NUM_M.equals(ruleMap.get(productId).getClearingRule())) {
                // 商户固定金额
                platformAmount = subAmount - (ruleMap.get(productId).getMerchantFix() * productCount);
            } else {
                // 清分规则异常
                throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_RULE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_RULE_ERROR.getMessage());
            }
        } else if (!SettlementRuleResVO.SETTLEMENT_TYPE_SELF.equals(ruleMap.get(productId).getSettlementType()) && !SettlementRuleResVO.SETTLEMENT_TYPE_PLATFORM.equals(ruleMap.get(productId).getSettlementType())) {
            // 非正常的结算类型
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR.getMessage());
        }

        return platformAmount;
    }

    @Override
    public Integer countSubPlatformAmountNew(Integer subAmount, Integer productCount, SettlementRuleResVO ruleDTO) {
        // 自营、平台默认平台抽佣金额为0
        int platformAmount = 0;
        // 查无清分规则
        if (null == ruleDTO) {
            log.error("未查询到商品清分规则，productId");
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_NO_RULE, null, BusinessErrorInfoEnum.CHANNEL_PAY_NO_RULE.getMessage());
        }

        // 清分
        if (SettlementRuleResVO.SETTLEMENT_TYPE_CLEAR.equals(ruleDTO.getSettlementType())) {
            if (SettlementRuleResVO.CLEARING_RULE_RATE.equals(ruleDTO.getClearingRule())) {
                // 百分比
                platformAmount = ruleDTO.getPlatformPre().multiply(new BigDecimal(subAmount)).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).intValue();
            } else if (SettlementRuleResVO.CLEARING_RULE_NUM_P.equals(ruleDTO.getClearingRule())) {
                // 平台固定金额
                platformAmount = ruleDTO.getPlatformFix() * productCount;
            } else if (SettlementRuleResVO.CLEARING_RULE_NUM_M.equals(ruleDTO.getClearingRule())) {
                // 商户固定金额
                platformAmount = subAmount - (ruleDTO.getMerchantFix() * productCount);
            } else {
                // 清分规则异常
                throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_RULE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_RULE_ERROR.getMessage());
            }
        } else if (!SettlementRuleResVO.SETTLEMENT_TYPE_SELF.equals(ruleDTO.getSettlementType()) && !SettlementRuleResVO.SETTLEMENT_TYPE_PLATFORM.equals(ruleDTO.getSettlementType())) {
            // 非正常的结算类型
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR.getMessage());
        }

        return platformAmount;
    }

    @Override
    public Integer platformAmountCommissionMerchantSettleRule(Integer subAmount, SettlementRuleResVO ruleVO) {
        // 查无清分规则
        if (null == ruleVO) {
            log.error("未查询到商户清分规则！！");
            throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_NO_RULE, null, BusinessErrorInfoEnum.CHANNEL_PAY_NO_RULE.getMessage());
        }
        // 自营、平台默认平台抽佣金额为0
        int platformAmount = 0;
        if (SettlementRuleResVO.SETTLEMENT_TYPE_CLEAR.equals(ruleVO.getSettlementType())) {
            if (SettlementRuleResVO.CLEARING_RULE_RATE.equals(ruleVO.getClearingRule())) {
                // 百分比
                platformAmount = ruleVO.getPlatformPre().multiply(new BigDecimal(subAmount)).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).intValue();
            } else if (SettlementRuleResVO.CLEARING_RULE_NUM_P.equals(ruleVO.getClearingRule())) {
                // 平台固定金额
                // platformAmount = ruleVO.getPlatformFix() * productCount;
                throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR.getMessage());

            } else if (SettlementRuleResVO.CLEARING_RULE_NUM_M.equals(ruleVO.getClearingRule())) {
                // 商户固定金额
                //platformAmount = subAmount - (ruleDTO.getMerchantFix() * productCount);
                throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_SETTLE_ERROR.getMessage());
            } else {
                // 清分规则异常
                throw new BusinessException(BusinessErrorInfoEnum.CHANNEL_PAY_RULE_ERROR, null, BusinessErrorInfoEnum.CHANNEL_PAY_RULE_ERROR.getMessage());
            }
        }
        if (platformAmount < 0) {
            platformAmount = 0;
        }
        return platformAmount;
    }

    /**
     * 查询子商户（子商户）信息
     *
     * @param merchantChannelRequestDTOS 查询参数
     * @return
     */
    @Override
    public Map<String, MerchantBO> getMerchantInfo(List<MerchantChannelRequestDTO> merchantChannelRequestDTOS) {
        Map<String, MerchantBO> merchantMap = new HashMap<>();
        final List<MerchantChannelRequestDTO> notCached = new ArrayList<>();
        for (MerchantChannelRequestDTO mrd : merchantChannelRequestDTOS) {
            try {
                final Optional<MerchantBO> mb = MerchantCache.getCachePaymentMerchant(mrd.getMerchantCode(), mrd.getPaymentChannelCode());
                if (mb.isPresent()) {
                    log.info("从缓存中查询商户进件信息,merchant_code:{},pay_channel:{}", mrd.getMerchantCode(), mrd.getPaymentChannelCode());
                    merchantMap.put(mrd.getMerchantCode(), mb.get());
                    continue;
                }
                notCached.add(mrd);
            } catch (Exception e) {
                notCached.add(mrd);
                log.error("从缓存中查询商户进件信息异常：", e);
            }
        }
        if (!CollectionUtils.isEmpty(notCached)) {
            // 缓存中不存在，查询一次
            List<MerchantChannelResponseDTO> merchantChannelResult = paymentMerchantPlatformService.queryByMerchantCodeAndChannel(notCached);
            log.info("缓存中没有商户进件信息，查询商户的渠道进件信息:{}", JsonUtil.toJsonString(merchantChannelResult));
            // 原始商户渠道进件数量，商户号和渠道号一致视为同一进件商户
            int regionSize = notCached.stream().map(m -> (m.getMerchantCode() + "-" + m.getPaymentChannelCode())).collect(Collectors.toSet()).size();
            // 判断商户是否均进件
            //BusinessErrorInfoEnum.CHANNEL_PAY_NO_MERCHANT.assertIsTrue(merchantChannelResult.size() == regionSize);
            merchantChannelResult.forEach(m -> {
                // 缺少商户号，视为商户未进件完成
                BusinessErrorInfoEnum.CHANNEL_PAY_NO_MERCHANT.assertIsTrue(StringUtils.isNotEmpty(m.getMerchantCode()));
                MerchantBO merchantBO = new MerchantBO();
                merchantBO.setMerchantRegId(m.getMerchantRegId());
                merchantBO.setMerchantCode(m.getMerchantCode());
                merchantBO.setSubAppid(m.getSubAppid());
                merchantBO.setEnterpriseCode(m.getEnterpriseCode());
                merchantMap.put(m.getMerchantCode(), merchantBO);
                MerchantCache.cachePaymentMerchant(m.getMerchantCode(), m.getPaymentChannelCode(), merchantBO);
            });
        }
        return merchantMap;
    }

    /**
     * 根据清分规则编码查询清分个规则
     *
     * @param ruleCodes 规则编码
     * @return key=M编码、P编码
     */
    @Override
    public Map<String, SettlementRuleResVO> querySettleRules(Set<String> ruleCodes) {
        if (CollectionUtils.isEmpty(ruleCodes)) {
            return MapUtils.EMPTY_SORTED_MAP;
        }
        Map<String, SettlementRuleResVO> rules = new HashMap<>();
        final List<String> mRuleCods = new ArrayList<>();
        final List<String> pRuleCOds = new ArrayList<>();
        for (String ruleCode : ruleCodes) {
            final Optional<SettlementRuleResVO> ruleOp = MerchantCache.getCachePaymentSettleRule(ruleCode);
            if(ruleOp.isPresent()){
                rules.put(ruleCode, ruleOp.get());
                continue;
            }
            String sourceRuleCode = ruleCode.substring(1);
            if (ruleCode.startsWith(SettleRuleTypeEnums.merchant.getCode())) {
                mRuleCods.add(sourceRuleCode);
            } else if (ruleCode.startsWith(SettleRuleTypeEnums.product.getCode())) {
                // 商品清分规则
                pRuleCOds.add(sourceRuleCode);
            }
        }
        queryRule(mRuleCods, SettleRuleTypeEnums.merchant, rules);
        queryRule(pRuleCOds, SettleRuleTypeEnums.product, rules);
        return rules;
    }

    /**
     * 查询商户、商品清分规则
     *
     * @param ruleCods
     * @param ruleTypeEnums
     * @param rules
     */
    private void queryRule(List<String> ruleCods, SettleRuleTypeEnums ruleTypeEnums, Map<String, SettlementRuleResVO> rules) {
        if (CollectionUtils.isNotEmpty(ruleCods) && ruleTypeEnums == SettleRuleTypeEnums.merchant) {
            // 商户清分规则
            final Result<List<SettlementRuleResVO>> result = merchantFeignService.queryOrderMerchantSettleRuleByMerchantRuleCods(ruleCods);
            if (result.getRet() == 0 && CollectionUtils.isNotEmpty(result.getData())) {
                for (SettlementRuleResVO r : result.getData()) {
                    MerchantCache.cachePaymentSettleRule(SettleRuleTypeEnums.merchant.getCode()+r.getSettleRuleCode(), r);
                    rules.put(ruleTypeEnums.getCode() + r.getSettleRuleCode(), r);
                }
            }
        }
        if (CollectionUtils.isNotEmpty(ruleCods) && ruleTypeEnums == SettleRuleTypeEnums.product) {
            // 商品清分规则
            final Result<List<SettlementRuleResVO>> result = settlementRuleService.getRulesByRuleCodes(ruleCods);
            if (result.getRet() == 0 && CollectionUtils.isNotEmpty(result.getData())) {
                for (SettlementRuleResVO r : result.getData()) {
                    MerchantCache.cachePaymentSettleRule(SettleRuleTypeEnums.product.getCode()+r.getSettleRuleCode(), r);
                    rules.put(ruleTypeEnums.getCode() + r.getSettleRuleCode(), r);
                }
            }
        }
    }


    /**
     * 查询清分规则集合
     *
     * @param orgPaymentChannelId
     * @param merchantCods
     * @return key-merchant
     */
    @Override
    public Map<String, List<SettlementRuleResVO>> querySettleRules(Long orgPaymentChannelId, List<String> merchantCods) {
        OrderMerchantSettleReqVO orderMerchantSettleReqVO = new OrderMerchantSettleReqVO();
        orderMerchantSettleReqVO.setOrgPaymentChannelId(orgPaymentChannelId);
        orderMerchantSettleReqVO.setMerchantCods(merchantCods);
        Result<List<SettlementRuleResVO>> result = merchantFeignService.queryOrderMerchantSettleRule(orderMerchantSettleReqVO);
        BusinessErrorInfoEnum.SYSTEM_ERROR.assertIsTrue(result.getRet() == 0 && CollectionUtils.isNotEmpty(result.getData()), "获取商户清分信息异常！");
        // 清分规则信息
        return result.getData().stream().collect(Collectors.groupingBy(SettlementRuleResVO::getMerchantCode));
    }

    @Override
    public List<MerchantChannelResponseDTO> queryOrgSubMerchant(List<Long> orgPaymentChannelIds) {
        if (CollectionUtils.isEmpty(orgPaymentChannelIds)) {
            return Collections.emptyList();
        }
        List<Long> queryOrgPayChannelIds=new ArrayList<>();
        List<MerchantChannelResponseDTO> result = new ArrayList<>();
        for (Long orgPaymentChannelId : orgPaymentChannelIds) {
            Optional<MerchantChannelResponseDTO> cacheOrgPayMerchant = MerchantCache.getCacheOrgPayMerchant(orgPaymentChannelId);
            if(cacheOrgPayMerchant.isEmpty()){
                queryOrgPayChannelIds.add(orgPaymentChannelId);
            }else{
                result.add(cacheOrgPayMerchant.get());
            }
        }
        if(CollectionUtils.isEmpty(queryOrgPayChannelIds)){
            return result;
        }
        // 查询
        Result<List<MerchantChannelResponseDTO>> listResult = merchantFeignService.queryOrgSubMerchant(queryOrgPayChannelIds);
        Asserts.isTrue(listResult.getRet()==0 && CollectionUtils.isNotEmpty(listResult.getData()),"查询平台分账子商户异常！");
        for (MerchantChannelResponseDTO datum : listResult.getData()) {
            MerchantCache.cacheOrgPayMerchant(datum.getOrgPaymentChannelId(),datum);
            result.add(datum);
        }
        return result;
    }

}
